//
//  NSMethodSignature+EXT.m
//  extobjc
//
//  Created by Justin Spahr-Summers on 2011-03-11.
//  Copyright (C) 2012 Justin Spahr-Summers.
//  Released under the MIT license.
//

#import "NSMethodSignature+EXT.h"

@implementation NSMethodSignature (EXTExtensions)

// 给方法签名添加参数返回一个新的方法签名
- (NSMethodSignature *)methodSignatureByInsertingType:(const char *)type atArgumentIndex:(NSUInteger)index {
    
    // 拿到参数的数量
    NSUInteger argumentCount = [self numberOfArguments];
    
    // 获取到type的长度
    size_t typeLength = strlen(type);

    // 获取到返回值的长度
    size_t stringLength = strlen([self methodReturnType]);
    
    // 遍历找到目标位置
    for (NSUInteger i = 0;i < argumentCount + 1;++i) {
        NSUInteger realIndex;
        
        if (i == index) { // 找到目标位置 字符串长度变为 （前半部分字符串 + 目标字符串）
            stringLength += typeLength;
            continue;
        } else if (i > index) { // 已经过了目标位置 下标 -1 取实际的参数位置
            realIndex = i - 1;
        } else { // 未到目标位置，下标对应实际的参数位置
            realIndex = i;
        }
        
        // 拿到对应的参数字符串
        const char *argType = [self getArgumentTypeAtIndex:realIndex];
        // 重新计算字符串长度
        stringLength += strlen(argType);
    }

	// 计算\0占的字节
	stringLength++;
    
    // 初始化对应的空间
    char *encoding = calloc(stringLength, 1);
    
    // 拷贝返回字符
    strlcpy(encoding, [self methodReturnType], stringLength);

    // 遍历并拷贝对应的字符串
    for (NSUInteger i = 0;i < argumentCount + 1;++i) {
        NSUInteger realIndex = i;
        const char *argType = NULL;

        if (i == index) {
            argType = type;     
        } else if (i > index) {
            realIndex = i - 1;
        }
        
        if (!argType)
            argType = [self getArgumentTypeAtIndex:realIndex];

		size_t currentLength = strlen(encoding);
        strlcpy(encoding + currentLength, argType, stringLength - currentLength);
    }
    
    // 生成对应的新的方法签名
    NSMethodSignature *newSignature = [NSMethodSignature signatureWithObjCTypes:encoding];
    free(encoding);

    return newSignature;
}

// 方法签名字符串
- (const char *)typeEncoding {
    
    // 获取到参数数量
    NSUInteger argumentCount = [self numberOfArguments];

    // 获取到返回值长度
    size_t stringLength = strlen([self methodReturnType]);
    
    // 计算总长度
    for (NSUInteger i = 0;i < argumentCount;++i) {
        const char *argType = [self getArgumentTypeAtIndex:i];
        stringLength += strlen(argType);
    }

    // 添加\0长度
	stringLength++;
    
    // 初始化字符串
    char *encoding = calloc(stringLength, 1);
    
    // 拷贝返回字符串
    strlcpy(encoding, [self methodReturnType], stringLength);

    for (NSUInteger i = 0;i < argumentCount;++i) {
        const char *argType = [self getArgumentTypeAtIndex:i];

		size_t currentLength = strlen(encoding);
        strlcpy(encoding + currentLength, argType, stringLength - currentLength);
    }

    // 创建一个未使用的NSData来自动释放allocated的字符串
    [NSData dataWithBytesNoCopy:encoding length:stringLength + 1 freeWhenDone:YES];

    return encoding;
}
@end
